﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// 实体组件改变委托
/// </summary>
/// <param name=""></param>
/// <param name="dex"></param>
/// <param name="com"></param>
public delegate void EntityCompoentChangeCallBack(ECSEntityBase entity, int index, ECSCompoentBase com);
/// <summary>
/// 实体组件替换委托
/// </summary>
/// <param name=""></param>
/// <param name="dex"></param>
/// <param name="com"></param>
/// <param name="newCom"></param>
public delegate void EntityCompoentReplaceCallBack(ECSEntityBase entity, int index, ECSCompoentBase com, ECSCompoentBase newCom);

/// <summary>
/// ECS实体基类
/// </summary>
public class ECSEntityBase
{
    
    #region world
    private ECSWorldBase m_world;

    public ECSWorldBase World
    {
        get { return m_world; }
        set { m_world = value; }
    }


    #endregion

    #region 实体id
    private int m_id;

    public int ID
    {
        get { return m_id; }
        set { m_id = value; }
    }


    #endregion

    #region MyRegion

    private string m_name;

    public string Name
    {
        get { return m_name;}
        set { m_name = value; }
    }
    

    #endregion
    #region 实体创建删除帧

    private int m_createFrame;
    private int m_destoryFrame;

    public int CreateFrame
    {
        get { return m_createFrame; }
        set { m_createFrame = value; }
    }

    public int DestoryFrame
    {
        get { return m_destoryFrame; }
        set { m_destoryFrame = value; }
    }

    #endregion

    #region 实体组件数组comps 未初始化分配空间
    public ECSCompoentBase[] comps;
    #endregion

    #region 实体哈希virtual

    public virtual int ToHash()
    {
        int hash = ID;
        if (comps==null)
        {
            return hash;
        }
        for (int i = 0,j=comps.Length; i < j; i++)
        {
            hash += comps[i].ToHash();
        }

        return hash;
    }
    

    #endregion

    #region 构造函数，初始化世界，组件数组comps new
    public ECSEntityBase(ECSWorldBase world)
    {
        World = world;
        comps = new ECSCompoentBase[world.compoentType.Count()];
    }
    #endregion

    #region 实体组件更改事件(添加/移除/替换)
    /// <summary>
    /// 实体组件添加事件
    /// </summary>
    public event EntityCompoentChangeCallBack OnCompoentAdd;
    /// <summary>
    /// 实体组件移除事件
    /// </summary>
    public event EntityCompoentChangeCallBack OnCompoentRemove;
    /// <summary>
    /// 实体组件替换事件
    /// </summary>
    public event EntityCompoentReplaceCallBack OnCompoentReplace;
    #endregion

    #region 询问实体是否包含某个组件类型/组件某个下标是否为空 GetExistCom
    /// <summary>
    /// 询问实体组件数组该下标是否为空
    /// </summary>
    /// <param name="compIndex"></param>
    /// <returns></returns>
    public bool GetExistCom(int compIndex)
    {
        return comps[compIndex] != null;
    }
    /// <summary>
    /// 询问实体是否包含某个组件类型
    /// </summary>
    /// <param name="comName"></param>
    /// <returns></returns>
    public bool GetExistCom(string comName)
    {
        int index = ToIndex(comName);
        return GetExistCom(index);
    }

    #endregion

    #region 组件类型名转索引

    public int ToIndex(string comName)
    {
        return m_world.compoentType.GetCompoentIndex(comName);
    }
    

    #endregion

    #region 实体组件添加
    /// <summary>
    /// 添加组件
    /// </summary>
    /// <param name="index"></param>
    /// <param name="com"></param>
    /// <returns>添加成功后的实体</returns>
    public ECSEntityBase AddComp(int index, ECSCompoentBase com)
    {
        
        if (GetExistCom(index))//如果组件列表此标志外有组件
        {
            throw new Exception("添加组件失败，实体id："+ID+"实体类型:"+this.GetType().Name+"要添加的组件下标:"+index+"不为空");
        }
        else
        {
            comps[index] = com;
            com.Entity = this;//指定实体
            com.World = m_world;//指定世界
            DisComAdd(this, index, com);//组件添加时的回调
            
        }

        return this;
    }

    public ECSEntityBase AddComp(string compName, ECSCompoentBase com)
    {
        int thisIndex = ToIndex(compName);
        AddComp(thisIndex, com);
        return this;
    }
    public ECSEntityBase AddComp<T>(T com)where T:ECSCompoentBase,new()
    {
        string comNameThis = typeof(T).Name;
        AddComp(comNameThis, com);
        return this;
    }

    public T AddComp<T>() where T : ECSCompoentBase, new()
    {
        T comThis=new T();//创建组件对象
        comThis.Init();//组件初始化
        AddComp(comThis);//添加组件
        return comThis;//返回组件
    }
    #endregion

    #region 实体组件移除
    public void RemoveCom(int index)
    {
        if (GetExistCom(index))
        {
            ECSCompoentBase com = comps[index];//获得该下标的组件
            comps[index] = null;//实体内该下标组件地址null
            DisComRemove(this, index, com);//移除组件回调
            com.GoNull();
        }
        else
        {
            throw new Exception("移除组件失败，下标为:"+index);
        }
    }

    public void RemoveCom(string comName)
    {
        int thisIndex = ToIndex(comName);
        RemoveCom(thisIndex);
    }

    public void RemoveCom<T>() where T : ECSCompoentBase, new()
    {
        RemoveCom(typeof(T).Name);
    }
    #endregion

    #region 实体组件获取

    public ECSCompoentBase GetCom(int index)
    {
        ECSCompoentBase go = comps[index];
        if (go !=null)
        {
            return go;
        }
        else
        {
            throw new Exception("获取组件失败,下标为：" + ID + "组件类型为:" + this.GetType().Name);
        }
    }
    public ECSCompoentBase GetCom(string comName)
    {
        int thisIndex = ToIndex(comName);
        return GetCom(thisIndex);
    }
    //获取组件转换为对应类型
    public T GetCom<T>(int index) where T : ECSCompoentBase, new()
    {
        T go = GetCom(index) as T;
        if (go !=null)
        {
            return go;
        }
        else
        {
            throw new Exception("获取组件失败");
        }
    }

    public T GetCom<T>() where T : ECSCompoentBase, new()
    {
        return GetCom<T>(ToIndex(typeof(T).Name));
    }
    #endregion

    #region 实体组件替换

    public void ChangeCom(int index, ECSCompoentBase com)
    {
        ECSCompoentBase comOld = comps[index];
        if (comOld !=null)
        {
            comps[index] = com;
            com.Entity = this;
            com.World = World;

            //组件替换回调
            DisComReplace(this, index, comOld, com);
            comOld.GoNull();
        }
        else
        {
            throw new Exception("组件替换失败，原索引："+index+"处组件为空");
        }
    }

    public void ChangeCom(string comName, ECSCompoentBase com)
    {
        int thisIndex = ToIndex(comName);
        ChangeCom(thisIndex,com);
    }

    public void ChangeCom<T>(int index, T com) where T : ECSCompoentBase, new()
    {
        ChangeCom(index,com);
    }

    public void ChangeCom<T>(T com) where T : ECSCompoentBase, new()
    {
        ChangeCom(typeof(T).Name,com);
    }
    #endregion

    #region 派发事件 组件更改时的事件
    //组件替换回调
    private void DisComReplace(ECSEntityBase entity,int index,ECSCompoentBase oldCom,ECSCompoentBase newCom)
   {
       if (OnCompoentReplace != null)
       {
           //组件替换回调
           OnCompoentReplace(entity, index, oldCom, newCom);
       }
    }
    //移除组件回调
    private void DisComRemove(ECSEntityBase entity, int index, ECSCompoentBase com)
   {
       if (OnCompoentRemove != null)
       {
           OnCompoentRemove(entity, index, com);//移除组件回调
       }
    }
    //组件添加时的回调
    private void DisComAdd(ECSEntityBase entity, int index, ECSCompoentBase com)
   {
       if (OnCompoentAdd != null)
       {
           OnCompoentAdd(entity, index, com);//组件添加时的回调
       }
    }

    #endregion
}

